using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

namespace AutoFormatter
{

    class AFParser
    {
        AFSettings settings;

        public AFParser(AFSettings settings)
        {
            this.settings = settings;
        }


        public string GetHTML(RichTextBox rtb)
        {
            SetProgressTarget(rtb);

            //create main body
            Div main = new Div();

            main.Style.Margin_Left = (int)settings.MarginLeft;
            main.Style.Margin_Right = (int)settings.MarginRight;
            main.Style.Border = settings.GetBorder();
            SetProgress(ProgressStages.MainDivCreated);

            //add the header if a block is being used
            if (settings.Showblock)
                main.Children.Add(GetHeader());
            SetProgress(ProgressStages.BlockCreated);            
            

            //add the actual text block
            main.Children.Add(GetTextBlock(rtb));
            SetProgress(progresstarget);

            //insert the ' . . . ' block
            if (settings.IsAllowed(BlockMode.Hide))
                main.Children.Add(GetHiddenBlock());

            //code for keydown
            if (settings.ShowSwitchModes)
            {
                main.OnKeyDown = "var k =event.keyCode,i=-1,ch=this.firstChild;if(k==32){i=ch.sel;if(++i==ch.selcount)i=0;}else i = k - 49;if(i>=0 && i<ch.selcount){ch.sel=i;ch.click();}";
            }

            StringBuilder sb = new StringBuilder();
            new Comment("--Start of code block\r\n").Append(sb);
            main.Append(sb);
            new Comment("\r\nEnd of code block--").Append(sb);
            return sb.ToString();
        }





        #region Progress

        private ToolStripProgressBar pb;

        public ToolStripProgressBar ProgressInterface
        {
            get { return pb; }
            set
            {
                pb = value;
                SetProgress(0);
            }
        }
        /// <summary>
        /// The different stages of progress.
        /// Unfortunately, I have to redo the entire
        /// progress thing, because I went with the stringbuilder
        /// approach after all. Althoug the good news is that I haven't
        /// had texts large enough
        /// </summary>
        enum ProgressStages
        {
            MainDivCreated = 2,
            BlockCreated = 4,
            StartRTFParsing
        }

        void SetProgress(int p)
        {
            if (pb != null)
            {
                pb.Value = p;
                Application.DoEvents();
            }
        }

        void SetProgress(ProgressStages ps)
        {
            SetProgress((int)ps);
        }

        void IncreaseProgress(int p)
        {
            SetProgress(pb.Value + p);
        }

        int progresstarget;
        void SetProgressTarget(RichTextBox rtb)
        {
            if (pb != null)
            {
                pb.Value = 0;
                pb.Maximum = progresstarget = (int)ProgressStages.StartRTFParsing + rtb.Rtf.Length / AFSettings.ProgressUpdateStep;
            }
        }

        #endregion


        #region Header

        const int selectedBorderWidth = 3;
        /// <summary>
        /// Formats the header with the style-switch control and copy link
        /// </summary>
        /// <returns></returns>
        Div GetHeader()
        {
            Div header = new Div();

            header.Style.Border_Bottom = settings.GetBorder();
            header.Style.CustomStyleSettings = settings.CustomHeaderStyle;

            if (settings.ShowSwitchModes)
            {
                //the script for switching hidden/scroll
                StringBuilder code = new StringBuilder();
                //variables declaration
                code.Append(@"var i=this.sel,j,ch,count = this.selcount;")
                    //check if the selection really changed/set selold
                    .Append("if(i==this.selold)return;this.selold=i;")
                    //start of loop to update appearance of swithmodes
                    .Append("for(j=0;j<count;j++){ch=this.childNodes[")
                    .Append(settings.UseCopyLink ? 2 : 1)
                    .Append("+j];");
                //alter check state if needed 
                if(settings.ButtonStyleHasCheckedMode)
                    code.Append("ch.childNodes[0].checked=j==i;");
                //set selected text bold
                code.Append("ch.style.fontWeight = j==i ? 'bolder' : 'normal';");
                //if the setting is enabled, use borders for the selected option
                if(settings.ShowSelectionBorder)
                    code.Append("ch.style.borderWidth=j==i?")
                        .Append(selectedBorderWidth).Append(":0;");
                //end of loop/prepare use of ch
                code.Append('}')
                    .Append("ch=parentNode.childNodes[1];");
                
                //in case code can be hidden, add code to show or hide the ... block
                int hideIndex=settings.AllowedIndexOf(BlockMode.Hide);
                if(hideIndex != -1)
                    code.Append("var sh=new Array('none','');")
                        .Append("j=i==").Append(hideIndex)
                        .Append("?0:1;ch.style.display=sh[j];ch.nextSibling.style.display=sh[1-j];");

                //in case scroll mode is used, check the height settings
                int scrollIndex= settings.AllowedIndexOf(BlockMode.Scroll);
                if(scrollIndex!=-1)
                    code.Append("var h =ch.offsetHeight;ch.style.height=i==")
                        .Append(scrollIndex)
                        .Append("?'").Append(settings.DefaultHeight).Append("pt':null;")
                        .Append("if(i==")
                        .Append(scrollIndex)
                        .Append("&& ch.offsetHeight>h)ch.style.height=h;");

                header.OnClick = code.ToString();

                Element<int> startas = new Element<int>(settings.AllowedStartAsIndex);
                header.AddAttribute("sel",startas.Value);
                header.AddAttribute("selold", startas);

                header.AddAttribute("selcount", settings.AllowedModesCount);
            }

            //set the text
            header.AddText(settings.HeaderText);

            //Add the copy link
            if (settings.UseCopyLink) 
            {
                Anchor a = new Anchor();
                a.href = "javascript:";
                a.OnClick = "window.clipboardData.setData('Text',this.parentNode.parentNode.childNodes[1].innerText);"
                    + (settings.ShowMessageAfterCopy 
                        ? "alert('Code copied to clipboard');"
                        : null);

                a.Style.Margin_Left = a.Style.Margin_Right = 10;
                a.AddText("Copy");
                header.Children.Add(a);
            }

            //Add the style switch controls (scroll,hidden,full)
            if (settings.ShowSwitchModes)
            {
                HtmlNode child=null;
                InputElement inp=null;
                int index = 0;
                BlockMode startMode = settings.AllowedStartAs;

                foreach(BlockMode bm in settings.AllowedModes)
                {
                    bool selected = bm == startMode;
                    string text =  bm.ToString();
                    if (settings.ButtonStyleHasSpans)
                    {
                        Span sp = new Span();
                        if (settings.ButtonStyleHasCheckedMode)
                        {
                            inp = settings.GetInputElement();
                            inp.OnClick = "this.blur();";
                            if (selected) inp.AddAttribute("Checked", true);
                            sp.Children.Add(inp);
                        }
                        sp.AddText(text);
                        sp.Style.Cursor = "hand";

                        sp.Style.Margin_Left = sp.Style.Margin_Right = 5;
                        
                        child = sp;
                    }
                    else if (settings.ButtonStyle == ButtonMode.Hyperlink)
                    {
                        child = new Anchor();
                        child.Style.Margin_Left = child.Style.Margin_Right = 10;
                        child.AddText(text);
                        (child as Anchor).href = "Javascript:";
                    }
                    else
                    {
                        child =inp = settings.GetInputElement();
                        inp.Value = text;
                    }


                    //if the current selectionmode is the start position
                    //indicate that it is just that
                    if (selected)
                    {
                        child.Style.Font_Weight = FontWeight.bolder;
                    }

                    if (settings.UseFixedWidth)
                        child.Style.Width = (int)settings.ButtonWidth;

                    if (settings.ShowSelectionBorder)
                    {
                        Border b = settings.GetBorder();
                        b.Width = selectedBorderWidth;
                        b.Style = BorderStyles.Double;
                        child.Style.Border = b;
                        if (!selected) b.Width = 0;
                    }

                    child.OnClick = "parentNode.sel=" +  index++.ToString(); 
                    header.Children.Add(child);
                    
                }
            }

            //Some watermarking. Of course you could take it out, but it would be
            //nice not to ;-)
            header.Children.Add(new Comment("CodeBlock by R.Verpalen 2005 : http://blogs.vbcity.com/hotdog/archive/2005/12/30/5759.aspx"));

            return header;
        }



        #endregion

        #region Text block


        Div GetTextBlock(RichTextBox rtb)
        {
            Div div = new Div();

            #region Style
            div.Style.overflow = "auto";
            div.Style.CustomStyleSettings = settings.CustomBlockStyle;

            //StartAs settings
            if (settings.AllowSwitchMode)
            {
                if (settings.AllowedStartAs == BlockMode.Hide)
                    div.Style.Display = "none";
                else if (settings.AllowedStartAs == BlockMode.Scroll)
                    div.Style.Height = (int)settings.DefaultHeight;
            }

            //Backcolor
            if (settings.Showblock)
                div.Style.BackGround_Color = settings.BackColor;


            #endregion

            //Convert the rtf text
            SetProgress(ProgressStages.StartRTFParsing);
            div.Children.Add(new RtfConverter(rtb.Rtf,(int)settings.TabSpaces,(int)settings.TabIndent));

            return div;

        }
        #endregion

        #region Hidden block

        private CanAppend GetHiddenBlock()
        {
            Div div = new Div();
            if (settings.StartAs != BlockMode.Hide)
                div.Style.Display = "none";
            div.Style.BackGround_Color = settings.BackColor;
            //div.Style.Cursor = "hand";
            div.OnDblClick = string.Format(
                "var o = parentNode.firstChild;o.sel ={0};o.click()",
                settings.StartAs == BlockMode.Hide ? 1 : settings.StartAsIndex);
            div.AddText("<b> . . .</b>");
            return div;
        }

        #endregion
    }
}
